﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace INSTA.Concepts.TemplateMethodPattern
{
    public class DelimitedFile : AbstractFile
    {
        private FileStream      _file;
        private StreamWriter    _sw;
        private StringBuilder   _sb;
        

        private const string SEPARATOR = ",";

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="person">The person.</param>
        /// <param name="fileName">Name of the file.</param>
        public DelimitedFile(Person person, string fileName) :base(person, fileName)
        {
            // Spécifie le nom de fichier, le mode d'ouverture du fichier et crée un nouveau Stream
            // pour écrire dans le fichier..
            _file = new FileStream(_fileName + ".csv", 
                                   FileMode.OpenOrCreate, 
                                   FileAccess.Write);
            
            _sw = new StreamWriter(_file);
            
            _sb = new StringBuilder();
        }



        /// <summary>
        /// Writes the File's header.
        /// </summary>
        public override void WriteHeader()
        {
            // On obtient le type de l'objet à faire persister 
            // dans le fichier.
            var type = typeof (Person);

            // On constitue une valeur de type BindingFlags qui 
            // nous indique de renvoyer TOUS les membres.
            var flags = BindingFlags.Public     |
                        BindingFlags.NonPublic  |
                        BindingFlags.Static     |
                        BindingFlags.Instance;

            // On boucle sur toutes les propriétés de l'objet 
            // à persister.
            foreach (var property in type.GetProperties(flags))
            {
                _sb.AppendFormat("{0}{1}", property.Name, SEPARATOR);
            }

            // on supprime la dernière virgule inutile..
            string headerLine = _sb.ToString();
            headerLine = headerLine.Substring(0, headerLine.Length - 1);

            // et l'on écrit la ligne d'en tête du fichier csv contenant les noms de champs..
            _sw.WriteLine(headerLine);
            
        }

        /// <summary>
        /// Writes the File's data.
        /// </summary>
        public override void WriteData()
        {
            _sb             = new StringBuilder();

            string dataLine = string.Empty;

            // On obtient par réflexion les valeurs de toutes les propriétés 
            // de l'objet Person traité, et on les concatène dans une chaine 
            // de caractères, séparées par un caractère "virgule"..
            foreach (var propInfo in typeof(Person).GetProperties(GetStandardBindings()))
            {
                _sb.AppendFormat("{0},", _person.GetPropertyValue(propInfo.Name));
            }

            // on supprime la dernière virgule inutile..            
            dataLine    = _sb.ToString();
            dataLine    = dataLine.Substring(0, dataLine.Length - 1);

            // et l'on écrit la ligne de données du fichier .csv
            _sw.Write(dataLine);            
        }

        /// <summary>
        /// Writes the File's footer.
        /// </summary>
        public override void WriteFooter()
        {
            // ferme le StreamWriter et le FileStream..
            _sw.Close();
            _file.Close();
        }
    }
}
